import {Layout} from '../../src/Layout';
export default Layout;

import {InlineAlert, Heading, Content} from '@react-spectrum/s2';
import docs from 'docs:@react-spectrum/s2';

export const tags = ['select', 'dropdown'];
export const relatedPages = [
  {title: 'Testing Picker', url: './Picker/testing'}
];
export const description = 'Displays a collapsible list of options, and allows a user to select one of them.';

# Picker

<PageDescription>{docs.exports.Picker.description}</PageDescription>

```tsx render docs={docs.exports.Picker} links={docs.links} props={['label', 'selectionMode', 'size', 'labelPosition', 'description', 'contextualHelp', 'isQuiet', 'isDisabled']} initialProps={{label: 'Ice cream flavor'}} type="s2"
import {Picker, PickerItem} from '@react-spectrum/s2';

<Picker/* PROPS */>
  <PickerItem>Chocolate</PickerItem>
  <PickerItem>Mint</PickerItem>
  <PickerItem>Strawberry</PickerItem>
  <PickerItem>Vanilla</PickerItem>
  <PickerItem>Chocolate Chip Cookie Dough</PickerItem>
</Picker>
```

## Content

`Picker` follows the [Collection Components API](collections?component=Picker), accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the `items` prop, and a function to render the children.

```tsx render
"use client";
import {Picker, PickerItem} from '@react-spectrum/s2';

function Example() {
  let options = [
    { id: 1, name: 'Aardvark' },
    { id: 2, name: 'Cat' },
    { id: 3, name: 'Dog' },
    { id: 4, name: 'Kangaroo' },
    { id: 5, name: 'Koala' },
    { id: 6, name: 'Penguin' },
    { id: 7, name: 'Snake' },
    { id: 8, name: 'Turtle' },
    { id: 9, name: 'Wombat' }
  ];

  return (
    /*- begin highlight -*/
    <Picker label="Animals" items={options}>
      {(item) => <PickerItem>{item.name}</PickerItem>}
    </Picker>
    /*- end highlight -*/
  );
}
```

### Slots

`PickerItem` supports icons, avatars, and `label` and `description` text slots.

```tsx render
"use client";
import {Avatar, Picker, PickerItem, Text} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import Comment from '@react-spectrum/s2/icons/Comment';
import Edit from '@react-spectrum/s2/icons/Edit';
import UserSettings from '@react-spectrum/s2/icons/UserSettings';

const users = Array.from({length: 5}, (_, i) => ({
  id: `user${i + 1}`,
  name: `User ${i + 1}`,
  email: `user${i + 1}@example.com`,
  avatar: 'https://i.imgur.com/kJOwAdv.png'
}));

<div className={style({display: 'flex', gap: 12, flexWrap: 'wrap'})}>
  <Picker label="Permissions" defaultValue="read">
    <PickerItem id="read" textValue="Read">
      {/*- begin highlight -*/}
      <Comment />
      <Text slot="label">Read</Text>
      <Text slot="description">Comment only</Text>
      {/*- end highlight -*/}
    </PickerItem>
    <PickerItem id="write" textValue="Write">
      <Edit />
      <Text slot="label">Write</Text>
      <Text slot="description">Read and write only</Text>
    </PickerItem>
    <PickerItem id="admin" textValue="Admin">
      <UserSettings />
      <Text slot="label">Admin</Text>
      <Text slot="description">Full access</Text>
    </PickerItem>
  </Picker>
  <Picker label="Share" items={users} defaultValue="user1">
    {(item) => (
      <PickerItem id={item.id} textValue={item.name}>
        {/*- begin highlight -*/}
        <Avatar slot="avatar" src={item.avatar} />
        {/*- end highlight -*/}
        <Text slot="label">{item.name}</Text>
        <Text slot="description">{item.email}</Text>
      </PickerItem>
    )}
  </Picker>
</div>
```

<InlineAlert variant="notice">
  <Heading>Accessibility</Heading>
  <Content>Interactive elements (e.g. buttons) within picker items are not allowed. This will break keyboard and screen reader navigation. Only add textual or decorative graphics (e.g. icons) as children.</Content>
</InlineAlert>

### Sections

Use the `<PickerSection>` component to group options. A `<Header>` element, with a `<Heading>` and optional `description` slot can be included to label a section. Sections without a header must have an `aria-label`.

```tsx render
"use client";
import {Picker, PickerSection, PickerItem, Header, Heading, Text} from '@react-spectrum/s2';

<Picker label="Ice cream flavor">
  {/*- begin highlight -*/}
  <PickerSection>
    <Header>
      <Heading>Neopolitan flavors</Heading>
      <Text slot="description">These flavors are common</Text>
    </Header>
    {/*- end highlight -*/}
    <PickerItem>Chocolate</PickerItem>
    <PickerItem>Strawberry</PickerItem>
    <PickerItem>Vanilla</PickerItem>
  </PickerSection>
  <PickerSection>
    <Header>
      <Heading>Others</Heading>
      <Text slot="description">These flavors are uncommon</Text>
    </Header>
    <PickerItem>Matcha</PickerItem>
    <PickerItem>Ube</PickerItem>
    <PickerItem>Prickly pear</PickerItem>
  </PickerSection>
</Picker>
```

### Asynchronous loading

Use the `loadingState` and `onLoadMore` props to enable async loading and infinite scrolling.

```tsx render
"use client";
import {Picker, PickerItem, useAsyncList} from '@react-spectrum/s2';

interface Character {
  name: string
}

function AsyncLoadingExample() {
  let list = useAsyncList<Character>({
    async load({signal, cursor}) {
      let res = await fetch(
        cursor || `https://pokeapi.co/api/v2/pokemon`,
        { signal }
      );
      let json = await res.json();

      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <Picker
      aria-label="Pokemon"
      items={list.items}
      /*- begin highlight -*/
      loadingState={list.loadingState}
      onLoadMore={list.loadMore}>
      {/*- end highlight -*/}
      {(item) => <PickerItem id={item.name}>{item.name}</PickerItem>}
    </Picker>
  );
}
```

### Links

Use the `href` prop on a `<PickerItem>` to create a link. See the [client side routing guide](routing) to learn how to integrate with your framework. Link items in a `Picker` are not selectable.

```tsx render
"use client";
import {Picker, PickerItem} from '@react-spectrum/s2';

<Picker label="Project">
  <PickerItem href="https://example.com/" target="_blank">Create new…</PickerItem>
  <PickerItem>Proposal</PickerItem>
  <PickerItem>Budget</PickerItem>
  <PickerItem>Onboarding</PickerItem>
</Picker>
```

## Value

Use the `defaultValue` or `value` prop to set the selected item. The value corresponds to the `id` prop of an item. When `selectionMode="multiple"`, `value` and `onChange` accept an array. Items can be disabled with the `isDisabled` prop.

```tsx render docs={docs.exports.Picker} links={docs.links} props={['selectionMode']} wide
"use client";
import {Picker, PickerItem} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {useState} from 'react';

function Example(props) {
  let [animal, setAnimal] = useState("bison");

  return (
    <div>
      <Picker
        {...props}
        label="Pick an animal"
        ///- begin highlight -///
        /* PROPS */
        value={animal}
        onChange={setAnimal}
        ///- end highlight -///
      >
        <PickerItem id="koala">Koala</PickerItem>
        <PickerItem id="kangaroo">Kangaroo</PickerItem>
        <PickerItem id="platypus" isDisabled>Platypus</PickerItem>
        <PickerItem id="eagle">Bald Eagle</PickerItem>
        <PickerItem id="bison">Bison</PickerItem>
        <PickerItem id="skunk">Skunk</PickerItem>
      </Picker>
      <pre className={style({font: 'body'})}>Current selection: {JSON.stringify(animal)}</pre>
    </div>
  );
}
```

## Forms

Use the `name` prop to submit the `id` of the selected item to the server. Set the `isRequired` prop to validate that the user selects an option, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more.

```tsx render docs={docs.exports.Picker} links={docs.links} props={['isRequired', 'necessityIndicator']} initialProps={{isRequired: true}} type="s2" wide
"use client";
import {Picker, PickerItem, Form, Button} from '@react-spectrum/s2';

function Example(props) {
  return (
    <Form>
      <Picker
        {...props}
        label="Animal"
        /*- begin highlight -*/
        name="animal"
        /* PROPS */
        /*- end highlight -*/
        description="Please select an animal.">
        <PickerItem id="aardvark">Aardvark</PickerItem>
        <PickerItem id="cat">Cat</PickerItem>
        <PickerItem id="dog">Dog</PickerItem>
        <PickerItem id="kangaroo">Kangaroo</PickerItem>
        <PickerItem id="panda">Panda</PickerItem>
        <PickerItem id="snake">Snake</PickerItem>
      </Picker>
      <Button type="submit">Submit</Button>
    </Form>
  );
}
```

## Popover options

The open state of the Picker can be controlled via the `defaultOpen` and `isOpen` props. The `align`, `direction`, `shouldFlip` and `menuWidth` props control the behavior of the popover.

```tsx render hideImports docs={docs.exports.Picker} links={docs.links} props={['align', 'direction', 'shouldFlip', 'menuWidth']}
"use client";
import {Picker, PickerItem} from '@react-spectrum/s2';
import {useState} from 'react';

function Example(props) {
  let [open, setOpen] = useState(false);

  return (
    <div>
      <p>Select is {open ? 'open' : 'closed'}</p>
      <Picker
        {...props}
        label="Choose frequency"
        /*- begin highlight -*/
        /* PROPS */
        isOpen={open}
        onOpenChange={setOpen}>
        {/*- end highlight -*/}
        <PickerItem id="rarely">Rarely</PickerItem>
        <PickerItem id="sometimes">Sometimes</PickerItem>
        <PickerItem id="always">Always</PickerItem>
      </Picker>
    </div>
  );
}
```

## API

```tsx links={{Picker: '#picker', PickerItem: '#pickeritem', PickerSection: '#pickersection', Icon: 'icons', Avatar: 'Avatar'}}
<Picker>
  <PickerItem>
    <Icon /> or <Avatar />
    <Text slot="label" />
    <Text slot="description" />
  </PickerItem>
  <PickerSection>
    <Header>
      <Heading />
      <Text slot="description" />
    </Header>
    <PickerItem />
  </PickerSection>
</Picker>
```

### Picker

<PropTable component={docs.exports.Picker} links={docs.links} />

### PickerItem

<PropTable component={docs.exports.PickerItem} links={docs.links} />

### PickerSection

<PropTable component={docs.exports.PickerSection} links={docs.links} />
